#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include "drv_ospi.h"
#include "dev_spi_flash_sfud.h"
#include <dfs_fs.h>

#define OSPI_BUS_NAME "ospi1"
#define OSPI_DEVICE_NAME "ospi10"
#define OSPI_FLASH_DEVICE_NAME "W25Q64Q"

static struct rt_qspi_device *ospi_dev;
extern rt_err_t rt_hw_ospi_device_attach(
    const char *bus_name, 
    const char *device_name, 
    rt_base_t cs_pin, 
    rt_uint8_t data_line_width, 
    void (*enter_qspi_mode)(), 
    void (*exit_qspi_mode)()
);

/* OSPI Flash初始化 */
int ospi_flash_init(void)
{
    rt_err_t res;
    
    /* 挂载OSPI设备 */
    res = rt_hw_ospi_device_attach(OSPI_BUS_NAME, OSPI_DEVICE_NAME, GET_PIN(B,10), 4, RT_NULL, RT_NULL);
    if (res != RT_EOK)
    {
        rt_kprintf("OSPI device attach failed!\n");
        return -RT_ERROR;
    }
    
    /* 查找SPI设备 */
    ospi_dev = (struct rt_qspi_device *)rt_device_find(OSPI_DEVICE_NAME);
    if (!ospi_dev)
    {
        rt_kprintf("Find OSPI device failed!\n");
        return -RT_ERROR;
    }

    /* 配置OSPI设备 */
    struct rt_qspi_configuration cfg={
        .parent={
            .mode=RT_SPI_MODE_0|RT_SPI_MSB,
            .max_hz=10*1000*1000,
            .data_width=8,
           },
        .qspi_dl_width=4,
    };
    if (rt_qspi_configure(ospi_dev, &cfg) != RT_EOK)
    {
        rt_kprintf("OSPI configure failed!\n");
        return -RT_ERROR;
    }
    
    rt_kprintf("OSPI Flash init success!\n");

    if (RT_NULL == rt_sfud_flash_probe(OSPI_FLASH_DEVICE_NAME, OSPI_DEVICE_NAME))
    {
        return -RT_ERROR;
    };

    #ifdef BSP_QSPI_FLASH_MOUNT_FATFS
    if (dfs_mount(OSPI_FLASH_DEVICE_NAME, "/qspi", "elm", 0, 0) != 0)
    {
        LOG_W("mount to '/qspi' failed! try to mkfs %s", OSPI_FLASH_DEVICE_NAME);
        dfs_mkfs("elm", OSPI_FLASH_DEVICE_NAME);
        if (dfs_mount(OSPI_FLASH_DEVICE_NAME, "/qspi", "elm", 0, 0) == 0)
        {
            LOG_I("mount to '/qspi' success!");
            goto _exit;
        }
    }
    LOG_I("mount to '/qspi' success!");
    #endif

_exit:
    return RT_EOK;
}

INIT_APP_EXPORT(ospi_flash_init);


static int rt_qspi_send_msg_test1(void)
{
    // struct rt_qspi_device *lcd_dev = (struct rt_qspi_device *)rt_device_find("qspi10");
    struct rt_qspi_message msg={
       .parent={
           .send_buf=(uint8_t []){0x11, 0x22, 0x33, 0x44, 0x55},
           .recv_buf=RT_NULL,
           .length=5,
           .cs_take=1,
           .cs_release=1,
           .next=RT_NULL,
       },
       .instruction={
           .content=0x02,
           .qspi_lines=1,
       },
      .address={
          .content=0x003A00,
          .size=24,
          .qspi_lines=1,
       },
      .alternate_bytes={
          .content=0x00,
          .size=0,
          .qspi_lines=0,
       },
      .dummy_cycles=0,
      .qspi_data_lines=1,
    };
    rt_qspi_transfer_message(ospi_dev, &msg);

    return RT_EOK;
}

MSH_CMD_EXPORT(rt_qspi_send_msg_test1, rt_qspi_send_msg_test1!);

/* 读取Flash ID */
static rt_uint32_t ospi_flash_read_id(void)
{
    uint8_t id_buf[3] = {0};  // 定义具体类型的缓冲区
    rt_qspi_send_then_recv(ospi_dev, (uint8_t[]){0x9F}, 1, id_buf, 3);
    return (id_buf[0] << 16) | (id_buf[1] << 8) | id_buf[2];  // 使用具体类型的缓冲区
}


/* 等待Flash操作完成 */
static void ospi_flash_wait_busy(void)
{
    uint8_t status;   
    do {
        rt_qspi_send_then_recv(ospi_dev, (uint8_t[]){0x05}, 1, &status, 1);
    } while(status & 0x01);  // 等待BUSY位清零
}

/* 扇区擦除 */
void ospi_flash_sector_erase(uint32_t addr)
{
    rt_qspi_send(ospi_dev, (uint8_t []){0x06}, 1);
    rt_qspi_send(ospi_dev, (uint8_t []){0x20, (addr>>16)&0xff, (addr>>8)&0xff, addr&0xff}, 4);
    
    // 等待擦除完成
    ospi_flash_wait_busy();
}

/* 页编程 */
void ospi_flash_page_program(uint32_t addr, const uint8_t *data, uint32_t size)
{
    rt_qspi_send(ospi_dev, (uint8_t []){0x06}, 1);

    // 发送页编程命令和数据
    struct rt_qspi_message msg = {
        .parent = {
            .send_buf = data,
            .recv_buf = RT_NULL,
            .length = size,
            .cs_take = 1,
            .cs_release = 1,
            .next = RT_NULL,
        },
        .instruction = {
            .content = 0x32,  // PAGE_PROGRAM命令
            .qspi_lines = 1,
        },
        .address = {
            .content = addr,
            .size = 24,
            .qspi_lines = 1,
        },
        .qspi_data_lines = 4,
    };
    rt_qspi_transfer_message(ospi_dev, &msg);
    
    // 等待写入完成
    ospi_flash_wait_busy();
}

/* 快速读取(四线模式) */
void ospi_flash_fast_read(uint32_t addr, uint8_t *buf, uint32_t size)
{
    struct rt_qspi_message msg = {
        .parent = {
            .send_buf = RT_NULL,
            .recv_buf = buf,
            .length = size,
            .cs_take = 1,
            .cs_release = 1,
            .next = RT_NULL,
        },
        .instruction = {
            .content = 0x6B,  // FAST_READ命令
            .qspi_lines = 1,
        },
        .address = {
            .content = addr,
            .size = 24,
            .qspi_lines = 1,
        },
        .dummy_cycles = 8,  // 快速读取需要8个dummy周期
        .qspi_data_lines = 4,  // 四线模式
    };
    rt_qspi_transfer_message(ospi_dev, &msg);
}


/* 测试函数 */
static void ospi_flash_test(int argc, char **argv)
{
    rt_uint32_t id;
    rt_uint8_t buf[256];
    rt_uint8_t test_buf[256];
    
    /* 读取ID */
    id = ospi_flash_read_id();
    rt_kprintf("Flash ID: 0x%06X\n", id);
    
    /* 擦除测试扇区 */
    rt_kprintf("Erasing sector at 0x000000...\n");
    ospi_flash_sector_erase(0x000000);
    rt_kprintf("Erase completed\n");
    
    /* 测试写入 */
    rt_memset(test_buf, 0x5A, sizeof(test_buf));
    rt_kprintf("Writing test data...\n");
    ospi_flash_page_program(0x000000, test_buf, sizeof(test_buf));
    rt_kprintf("Write completed\n");
    
    /* 读取验证 */
    rt_memset(buf, 0, sizeof(buf));
    rt_kprintf("Reading back data...\n");
    ospi_flash_fast_read(0x000000, buf, sizeof(buf));
    
    /* 验证数据 */
    if (rt_memcmp(test_buf, buf, sizeof(test_buf)) == 0)
    {
        rt_kprintf("OSPI Flash test success!\n");
    }
    else
    {
        rt_kprintf("OSPI Flash test failed!\n");
        rt_kprintf("Expected: ");
        for(int i=0; i<16; i++) rt_kprintf("%02X ", test_buf[i]);
        rt_kprintf("\nActual:   ");
        for(int i=0; i<16; i++) rt_kprintf("%02X ", buf[i]);
        rt_kprintf("\n");
    }
}
MSH_CMD_EXPORT(ospi_flash_test, ospi_flash_test!);